/**
 https://www.jb51.net/article/158904.htm
 https://www.zhihu.com/question/21308647
*/

let factories = {};
let modules = {};

function require(name){
  if (modules[name]){
    return modules[name];
  }

  /** emmm script发起请求应该不是在require阶段 而是define函数执行阶段,define函数执行时,会扫描它绑定factory函数(通过fn.toString()获得函数的内容),利用正则匹配匹配(require("xxx")这样的,然后此时会用script去下载这些模块) */
  /** 参看fn.js*/
  let script = document.createElement('script');
  script.src = name;
  document.head.appendChild(script);

  script.onload = function () {
    document.head.removeChild(script);
    let factory = factories[name];
    let exports = {};

    // 放在factory()调用之前 就能实现循环引用 这样循环引用时得到的就是{}
    // map模式
    modules[name] = exports;

    factory(require, exports);
    // TODO 应该返回什么？
  };
}

function define(name, factory){
  factories[name] = factory;
}

function use(name){
  require(name)
}


//---
define('addModule', function (require, exports) {
  exports.add = function (a, b) {
    return a + b;
  }
});
define('minusModule', function (require, exports) {
  exports.minus = function (a, b) {
    return a - b;
  }
});
define('index', function (require, exports) {
  var addModule/** TODO 这里是怎么确保拿到addModule的导出的(`require('addModule')`方法明明可能是异步的)*/ = require('addModule');

  /**
    一个模块文件被浏览器下载下来后，并不会直接运行我们的模块定义代码，而是会首先执行一个define函数，这个函数会取得模块定义的源代码（通过函数的toString()函数来取得源代码），然后利用正则匹配找到依赖的模块（匹配require("dep.js")这样的字符串)，然后加载依赖的模块，最后发射一个自定义事件complete，通知当前模块， 模块已经加载完成，此时，当前模块的就会调用与complete事件绑定的回调函数，完成与这个模块相关的任务，比如resolve与这个模块加载绑定的Promise。
  */

  let result1 = addModule.add(1, 2);
  console.log(result1);
  var minusModule = require('minusModule');
  let result2 = minusModule.minus(1, 2);
  console.log(result2);
});
use('index');
